/*
功能：基于单个IO的按键程序
时间：2019-03-27
作者：Lhuan
更新记录：
1）2018-03-06：长按事件函数1个返回值变为两个返回值，value：按键ID，value2：长按时间

*/
#include "user_key2.h"

//设置按键按下后，硬件IO获取到的是低电平还是高电平
const uint8 user_key_down_hardware_state[USER_KEY_COUNT]=USER_KEY_DOWN_HARDWARE_STATE;


//获取io硬件状态的函数接口
KeyIoHardwareStateGet hardwareStateGet_=0;

///*定义事件响应指针*/
KeyEventCallback p_up=0;				//松开事件
KeyEventCallback p_longdown=0;		//长按事件
KeyEventCallback p_down=0;          //按下事件
KeyEventCallback p_downcount=0;     	//连续按下事件



/*
按键IO初始化
*/
void user_key_init(KeyIoHardwareStateGet state_get,KeyEventCallback upx,KeyEventCallback downTime,KeyEventCallback longdownx,KeyEventCallback downCount)
{
	hardwareStateGet_=state_get;
	p_up=upx;
	p_down=downTime;
	p_longdown=longdownx;
	p_downcount=downCount;
}

/*
扫描硬件io状态
然后输出按键扫描结果，按下的按键对应的标志位设置为1，否则对应位为0
*/
uint32 user_key_scan(void)
{
    uint32 keyvalue=0,base_value=0x01;
    uint8 key_i;
    for(key_i=0,base_value=0x01;key_i<USER_KEY_COUNT;key_i++,base_value<<=1)
    {
        if(hardwareStateGet_)
        {
            if(hardwareStateGet_(key_i)==user_key_down_hardware_state[key_i])
            {
                keyvalue|=base_value;
            }
        }
    }
    return keyvalue;
}
    static uint16 key_downtime[USER_KEY_COUNT];
    static uint16 key_uptime[USER_KEY_COUNT];
    static uint16 key_count[USER_KEY_COUNT];
void user_key_run(uint16 divtime)
{


    static uint8 firstrun=0,key_i;
    
    static uint32 value=0,historyvalue=0;
    uint32 upvalue=0,downvalue=0,base_value=0x01;
    
    value=user_key_scan();

    if(firstrun==0)
    {//首次运行函数，因为没有参考，所以首次扫描值不做处理
        firstrun=1;
        historyvalue=value;
        return ;
    }

    if(value^historyvalue)//按键值有变化
    {
        //获取到按键松开的数据值
        upvalue=(value^historyvalue)&historyvalue;
        
        //获取到按键按下的数据值
        downvalue=(value^historyvalue)&value;
        
        //使用完毕后将本次扫描数据再次记录为历史值
        historyvalue=value;
        //
        for(key_i=0,base_value=0x01;key_i<USER_KEY_COUNT;key_i++,base_value<<=1)
        {
            if(upvalue&base_value)
            {
                if(p_up)p_up(key_i,key_downtime[key_i]);
                key_uptime[key_i]=0;
            }
            if(downvalue&base_value)
            {
                if(p_down)p_down(key_i,key_uptime[key_i]);
                
                if(key_count[key_i]==0)
                {
                    key_count[key_i]++;
                }
                else if(key_uptime[key_i]<=SHORT_DOWN_TIME_MS)
                {
                        key_count[key_i]++;
                }
                else key_count[key_i]=1;
                key_downtime[key_i]=0;
            }
        }
    }
    for(key_i=0,base_value=0x01;key_i<USER_KEY_COUNT;key_i++,base_value<<=1)
    {
        //按键按下判断
        if(value&base_value)
        {
            //按下计时
            if(key_downtime[key_i]<60000)key_downtime[key_i]+=divtime;
            //长按事件触发标志置1
            if(p_longdown&&key_downtime[key_i]>=USER_KEY_LONG_DOWN_TIG_TIME)
            {
                p_longdown(key_i,key_downtime[key_i]);
            }
        }
        else 
        {
            key_downtime[key_i]=0;
            if(key_uptime[key_i]<30000)key_uptime[key_i]+=divtime;
            if(key_count[key_i]!=0&&key_uptime[key_i]>=SHORT_DOWN_TIME_MS)
            {
                if(p_downcount&&key_downtime[key_i]<=CLICK_TIME_OUT)p_downcount(key_i,key_count[key_i]);
                key_count[key_i]=0;
            }
        }
    }
}


